using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.ComponentModel;

using BeeDevelopment.Brass3;
using BeeDevelopment.Brass3.Attributes;
using BeeDevelopment.Brass3.Plugins;
using System.Reflection;

namespace Core.Listing {

	[Category("Debugging")]
	[Remarks("resources://Core.Documentation/EmukonPatchRemarks")]
	[Description("resources://Core.Documentation/EmukonPatchDescription")]

	public class EmukonPatch : IListingWriter {

		public void WriteListing(Compiler compiler, Stream stream) {
			
			// Create a TextWriter to write the patch file to.
			TextWriter ListWriter = new StreamWriter(stream, Encoding.ASCII);

			// Some descriptive comments...
			AssemblyName CoreName = typeof(EmukonPatch).Assembly.GetName();
			AssemblyName BrassName = typeof(BeeDevelopment.Brass3.Compiler).Assembly.GetName();
			ListWriter.WriteLine(";; Patch file for {4} generated by {0} {1} ({2} {3}).", CoreName.Name, CoreName.Version, BrassName.Name, BrassName.Version, Path.GetFileNameWithoutExtension(compiler.Project.ProjectFilename));
			
			// Dump labels:
			foreach (var L in compiler.Labels) {
				
				if (L.Exported && L != compiler.Labels.ProgramCounter && !string.IsNullOrEmpty(L.Name) && !L.IsString) {

					/*
					Label   <address>, <name>  adds a label
					VarB    <address>, <name>  adds a byte variable
					VarW    <address>, <name>  adds a word variable
					VarD    <address>, <name>  adds a dword variable
					 */
					
					string LabelType;

					switch (L.Usage) {
						case Label.UsageType.Variable:
							switch (L.Size) {
								case 4:
									LabelType = "VarD";
									break;
								case 2:
									LabelType = "VarW";
									break;
								default:
									LabelType = "VarB";
									break;
							}
							break;
						default:
							LabelType = "Label";
							break;
					}
					ListWriter.WriteLine("{0}\t${1:X4}, {2}", LabelType, (int)L.NumericValue, L.Name);
				}
			}

			// Dump breakpoints:
			foreach (var Breakpoint in compiler.Breakpoints) {
				if ((Breakpoint.Trigger & Breakpoint.BreakpointTrigger.Execution) != Breakpoint.BreakpointTrigger.None) {
					ListWriter.WriteLine("BP\t${0:X4}", Breakpoint.Address);
				}
			}

			ListWriter.Flush();
		}
		
	}
}
